Team members: Chenran Peng, Qiaoling Huang, Shihan Li, Ziqin Ma, Elmira Ushirova

Introduction

The dataset that we are using for this project is sampled from a large dataset of Women's Shoes from Datafiniti database. It contains around 10,000 online women shoes listings from April 2015 to April 2019 (9,709 after data cleaning). The dataset has 32 columns and includes information such as name, brand, minimum and maximum prices, size, color, url links and additionals for each offered pair of women shoes. For the purposes of our analysis, we decided to focus mainly on some columns including date, price, brands, colors, name and size.

By analyzing this dataset, we would like to identify what trends the shoes manufacturers follow nowadays and what kind of pricing strategies shoe brands have now. Our expectation is to analyze the data in different dimensions and give conclusions and recommendations on shoe trends by answering these questions:

  1. Size
  1. Color
  1. Time
  1. Price

Get started: Data cleaning

In this project, we use the same dataset as the BA 770 one, and we have known that there are outliers. To do a more systematic analysis, we start with data cleaning and organizing.

Step 1: Load packages

install.packages("tidyverse")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/tidyverse_1.2.1.tgz'
Content type 'application/x-gzip' length 89217 bytes (87 KB)
==================================================
downloaded 87 KB

The downloaded binary packages are in
    /var/folders/x5/gtbnd5cj5rl0c9h7jtktvqn80000gn/T//RtmpUNMowA/downloaded_packages
install.packages("plotly")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/plotly_4.9.0.tgz'
Content type 'application/x-gzip' length 2801589 bytes (2.7 MB)
==================================================
downloaded 2.7 MB

The downloaded binary packages are in
    /var/folders/x5/gtbnd5cj5rl0c9h7jtktvqn80000gn/T//RtmpUNMowA/downloaded_packages
install.packages("ggplotly")
Warning in install.packages :
  package ‘ggplotly’ is not available (for R version 3.6.1)
install.packages("ggthemes")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/ggthemes_4.2.0.tgz'
Content type 'application/x-gzip' length 420298 bytes (410 KB)
==================================================
downloaded 410 KB

The downloaded binary packages are in
    /var/folders/x5/gtbnd5cj5rl0c9h7jtktvqn80000gn/T//RtmpUNMowA/downloaded_packages
install.packages("gridExtra")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/gridExtra_2.3.tgz'
Content type 'application/x-gzip' length 1103470 bytes (1.1 MB)
==================================================
downloaded 1.1 MB

The downloaded binary packages are in
    /var/folders/x5/gtbnd5cj5rl0c9h7jtktvqn80000gn/T//RtmpUNMowA/downloaded_packages
install.packages("ggpubr")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/ggpubr_0.2.3.tgz'
Content type 'application/x-gzip' length 1819911 bytes (1.7 MB)
==================================================
downloaded 1.7 MB

The downloaded binary packages are in
    /var/folders/x5/gtbnd5cj5rl0c9h7jtktvqn80000gn/T//RtmpUNMowA/downloaded_packages
# commands above can be skipped if these have already been installed on current working environment
library(readr)
library(tidyverse)
── Attaching packages ────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.2.1     ✔ purrr   0.3.2
✔ tibble  2.1.3     ✔ dplyr   0.8.3
✔ tidyr   1.0.0     ✔ stringr 1.4.0
✔ ggplot2 3.2.1     ✔ forcats 0.4.0
── Conflicts ───────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(ggplot2)
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(dplyr)
library(lubridate)

Attaching package: ‘lubridate’

The following object is masked from ‘package:base’:

    date
library(tidyr)
library(stringr)
library(ggthemes)
library(gridExtra)

Attaching package: ‘gridExtra’

The following object is masked from ‘package:dplyr’:

    combine
library(ggpubr)
Loading required package: magrittr

Attaching package: ‘magrittr’

The following object is masked from ‘package:purrr’:

    set_names

The following object is masked from ‘package:tidyr’:

    extract
women_shoes <- Final_version_Final_version_3_
options(stringsAsFactors = FALSE)

Check for the unique number of brands (before cleaning):

length(unique(women_shoes$brand))
[1] 494

Step 2: Clean special symbols in brand and drop all NAs

women_shoes <- drop_na(women_shoes)
women_shoes$brand <- tolower(women_shoes$brand)
women_shoes$brand <- gsub("-"," ",women_shoes$brand)
for (i in 1: nrow(women_shoes)) {
  if (women_shoes$brand[i] == "aeorosoles") {
    women_shoes$brand[i] <- "aerosoles"
  }
  if (women_shoes$brand[i] == "bamboo Brand" ) {
    women_shoes$brand[i] <- "bamboo"
  }
  if (women_shoes$brand[i] ==  "baretraps") {
    women_shoes$brand[i] <- "bare traps"
  }
  if (women_shoes$brand[i] == "beacon" ) {
    women_shoes$brand[i] <- "beacon shoes"
  }
  if (women_shoes$brand[i] == "benjamin walk" ) {
    women_shoes$brand[i] <- "benjamin walk dyeables"
  }
  if (women_shoes$brand[i] == "carlos by carlo santana" ) {
    women_shoes$brand[i] <- "carlos"
  } else if (women_shoes$brand[i] == "carlos by carlos santana") {
    women_shoes$brand[i] <- "carlos"
  }
  if (women_shoes$brand[i] == "cat footwear") {
    women_shoes$brand[i] <- "cat"
  }
  if (women_shoes$brand[i] == "charles by charles david") {
    women_shoes$brand[i] <- "charles david"
  }
  if (women_shoes$brand[i] == "cityclassified" ) {
    women_shoes$brand[i] <- "city classified"
  }
  if (women_shoes$brand[i] == "diba" ) {
    women_shoes$brand[i] <- "diba true"
  }
  if (women_shoes$brand[i] == "dr. scholl's shoes" ) {
    women_shoes$brand[i] <- "dr. scholl's"
  }
  if (women_shoes$brand[i] == "drew shoe" ) {
    women_shoes$brand[i] <- "drew"
  }
  if (women_shoes$brand[i] ==  "ellie shoes") {
    women_shoes$brand[i] <- "ellie"
  }
  if (women_shoes$brand[i] == "fergie footwear" ) {
    women_shoes$brand[i] <- "fergie"
  } else if (women_shoes$brand[i] == "fergie shoes") {
    women_shoes$brand[i] <- "fergie"
  }
  if (women_shoes$brand[i] ==  "genuine grip footwear") {
    women_shoes$brand[i] <- "genuine grip"
  }
  if (women_shoes$brand[i] == "j.rene") {
    women_shoes$brand[i] <- "j. renee"
  }
  if (women_shoes$brand[i] == "jbu by jambu" ) {
    women_shoes$brand[i] <- "jbu"
  }
  if (women_shoes$brand[i] ==  "koolaburra by ugg" ) {
    women_shoes$brand[i] <- "koolaburra"
  }
  if (women_shoes$brand[i] == "l'artiste by spring step" ) {
    women_shoes$brand[i] <- "lartiste"
  } else if (women_shoes$brand[i] == "lartiste by spring step") {
    women_shoes$brand[i] <- "lartiste"
  }
  if (women_shoes$brand[i] == "lauren by ralph lauren" ) {
    women_shoes$brand[i] <- "ralph lauren"
  } else if (women_shoes$brand[i] ==  "lauren ralph lauren" ) {
    women_shoes$brand[i] <- "ralph lauren"
  }
  if (women_shoes$brand[i] == "life stride" ) {
    women_shoes$brand[i] <- "lifestride"
  } else if (women_shoes$brand[i] ==   "lifestride shoes" ) {
    women_shoes$brand[i] <- "lifestride"
  }
  if (women_shoes$brand[i] == "michael michael kors" ) {
    women_shoes$brand[i] <- "michael kors"
  }
  if (women_shoes$brand[i] == "pleaserusa"  ) {
    women_shoes$brand[i] <- "pleaser usa"
  }
  if (women_shoes$brand[i] == "skechers work") {
    women_shoes$brand[i] <- "skechers"
  }
  if (women_shoes$brand[i] ==  "soda shoes"  ) {
    women_shoes$brand[i] <-"soda"
  }
  if (women_shoes$brand[i] ==   "soft style by hush puppies"  ) {
    women_shoes$brand[i] <-"soft style"
  }
  if (women_shoes$brand[i] == "softwalk footwear" ) {
    women_shoes$brand[i] <-"softwalk"
  }
  if (women_shoes$brand[i] ==  "sorel footwear" ) {
    women_shoes$brand[i] <-"sorel"
  }
  if (women_shoes$brand[i] ==  "sperry top  sider"  ) {
    women_shoes$brand[i] <- "sperry top sider"
  } else if (women_shoes$brand[i] ==  "sperry" ) {
    women_shoes$brand[i] <- "sperry top sider"
  }
  if (women_shoes$brand[i] ==  "summitfashions" ) {
    women_shoes$brand[i] <-"summit fashions"
  }
  if (women_shoes$brand[i] ==   "toms shoes"  ) {
    women_shoes$brand[i] <- "toms"
  }
  if (women_shoes$brand[i] ==  "ugg australia"  ) {
    women_shoes$brand[i] <-"ugg"
  }
  if (women_shoes$brand[i] ==  "vionic with orthaheel technology" ) {
    women_shoes$brand[i] <- "vionic"
  }
}
length(unique(women_shoes$brand))
[1] 390
glimpse(women_shoes)
Observations: 9,709
Variables: 9
$ id               <chr> "AWpyySsJAGTnQPR7wNt4", "AWpyyyb3AGTnQPR7wN-u", "AWpyzlajAG…
$ dateAdded        <date> 2019-05-01, 2019-05-01, 2019-05-01, 2019-05-01, 2019-05-01…
$ brand            <chr> "city classified", "skechers", "floral", "jambu", "trotters…
$ colors           <chr> "Black", "Taupe", "Black", "Black/Multi", "White", "Metalli…
$ name             <chr> "City Classified Stylish-S Women's Zipper Ankle Booties", "…
$ prices.amountMax <dbl> 29.95, 84.00, 49.95, 127.20, 47.66, 82.64, 79.95, 62.41, 62…
$ prices.amountMin <dbl> 29.95, 84.00, 49.95, 127.20, 47.66, 82.64, 79.95, 62.41, 62…
$ prices.offer     <chr> "Online only", "Online only", "Online only", "Online only: …
$ sizes            <chr> "8", "6", "5", "9.5", "11", "11", "9", "6", "5", "8", "7", …

1. Size

3. Time

When does retailers usually release new shoes

women_shoes$month <- months(as.Date(women_shoes$dateAdded))
women_shoes$year <- year(as.Date(women_shoes$dateAdded))
women_shoes%>%
  filter(year == "2015") -> new_date
ggplot(new_date, aes(x = month)) + 
    geom_bar(stat =  "count", na.rm = TRUE, fill = "darkseagreen3")

We limited our dataset to only one year range as our dataset have so many missing data, for example we only have data for April and May in 2019. Based on the result we can see that April and September are the month that most brand launch their new product follow by August, November and December. We can assume that most brand usually release their products for between two seasons.


4. Price

Data cleaning continued

In Price section, we need to further clean the dataset. We would like to change all the letters in name into lowercase and create a new dataframe called new_df.

women_shoes2 <- transform(women_shoes, lowname = tolower(name))
women_shoes2 %>% 
  group_by(id) %>% 
  mutate(
    prices = (prices.amountMax + prices.amountMin)/2
  ) %>% 
  select(id, dateAdded, brand, lowname, prices, prices.offer) -> new_df
head(new_df)

Then we want to find outliers through a boxplot gragh. Based on the result, we consider price over $500 are outliers.

tmp <- new_df %>% 
  ggplot(aes(x = 1, y = prices)) +
  geom_boxplot(color = "black") +
  coord_flip() +
  theme_classic()
ggplotly(tmp)

A new boxplot after we remove these outliers (prices > $500):

tmp0 <- new_df %>% 
  filter(prices < 500) %>% 
  ggplot(aes(x = 1, y = prices)) +
  geom_boxplot(color = "black") +
  coord_flip() +
  theme_classic()
ggplotly(tmp0)

Next, we exclude outliers and extract the pattern from name. We also create a new column category specifying different categories for each pair of shoes. Finally, we extract “off” from prices.offer and create a new column discount which indicates whether the price is on sale or not.

test1 <- new_df %>% 
  mutate(
    category = case_when(
      str_detect(lowname, pattern = "boot") ~ "boots",
      str_detect(lowname, pattern = "pump") ~ "pump",
      str_detect(lowname, pattern =  "sneaker") ~ "sneaker",
      str_detect(lowname, pattern = "sandal") ~ "sandal",
      str_detect(lowname, pattern = "flat") ~ "flat",
      str_detect(lowname, pattern = "slipper") ~ "slipper",
      str_detect(lowname, pattern = "loafer") ~ "loafer",
      str_detect(lowname, pattern = "clog") ~ "clog"
    ),
    discount = case_when(
      str_detect(prices.offer, pattern = "off") ~ "Yes",
      TRUE ~ "No"
    ) 
  ) %>% 
  filter(prices < 500)
test1$category[is.na(test1$category)] <- "others"
test1 %>% 
select(id, dateAdded, brand, lowname, prices, category, discount) %>% 
arrange(desc(prices))-> new_df2
head(new_df2)

Brands with widest price distribution

summary(women_shoes)
      id              dateAdded             brand              colors         
 Length:9709        Min.   :2015-04-01   Length:9709        Length:9709       
 Class :character   1st Qu.:2019-04-19   Class :character   Class :character  
 Mode  :character   Median :2019-04-19   Mode  :character   Mode  :character  
                    Mean   :2018-12-29                                        
                    3rd Qu.:2019-04-23                                        
                    Max.   :2019-05-01                                        
     name           prices.amountMax  prices.amountMin  prices.offer      
 Length:9709        Min.   :   5.00   Min.   :   5.00   Length:9709       
 Class :character   1st Qu.:  34.99   1st Qu.:  34.99   Class :character  
 Mode  :character   Median :  52.07   Median :  52.07   Mode  :character  
                    Mean   :  72.76   Mean   :  72.76                     
                    3rd Qu.:  85.77   3rd Qu.:  85.77                     
                    Max.   :5000.00   Max.   :5000.00                     
    sizes              month                year     
 Length:9709        Length:9709        Min.   :2015  
 Class :character   Class :character   1st Qu.:2019  
 Mode  :character   Mode  :character   Median :2019  
                                       Mean   :2019  
                                       3rd Qu.:2019  
                                       Max.   :2019  
glimpse(new_df2)
Observations: 9,691
Variables: 7
Groups: id [8,643]
$ id        <chr> "AWpIeaEfM263mwCq78AC", "AWoxI9NHAGTnQPR7qqIT", "AWpx5SOVAGTnQPR7v…
$ dateAdded <date> 2019-04-23, 2019-04-18, 2019-05-01, 2019-04-20, 2019-04-19, 2017-…
$ brand     <chr> "ugg", "asics", "easy street", "aerosoles", "lifestride", "easy st…
$ lowname   <chr> "ugg bailey bow tall ii women's shoes boots 1016434 black", "asics…
$ prices    <dbl> 383.26, 374.17, 346.65, 346.65, 346.65, 346.65, 346.65, 338.95, 31…
$ category  <chr> "boots", "others", "boots", "boots", "flat", "sandal", "sandal", "…
$ discount  <chr> "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", …
new_df2 %>%
  group_by(brand) %>%
  summarize(price_range=(max(as.numeric(prices))-min(as.numeric(prices))),
            count = n()) %>%
  select(brand, count, price_range) %>%
  arrange(desc(price_range)) -> df1
head(df1,10)

Last time we have some brand that have price range for around $5000, by working more on this dataset, we find out that there are some product sell for $5000. We did some data cleaning on this dataset to get rid of those outliers. After done with the data cleaning, we got our result for price distribution of each brand. Here are top 10 brand that have the widest price distribution range. We can see that brands usually have price range smaller than $350.

Price inspection on categories

We observe that boots habe the highest count and the average price is $67. Sandals have the second highest count and the average price is $57. More average prices are showned as below:

new_df2 %>% 
  group_by(category) %>% 
  summarize(
    avg_price_by_category = mean(prices, na.rm = TRUE),
    count= n()
  ) %>% 
  select(category, count, avg_price_by_category) %>% 
  arrange(avg_price_by_category)-> avg_price_category
head(avg_price_category, 9)

We make a summary of prices in different categories, and surprisely see that the average price in all categories are below $100.

tmp2 <- new_df2 %>% 
  filter(category != "others") %>% 
  ggplot(aes(x = category, y = prices)) +
  stat_summary(fun.y = "mean", fun.ymin = min, fun.ymax = max, colour = "#7C7F91") +
  geom_hline(yintercept = 100, linetype = "dashed", color = "red")+
  xlab("Category of Shoes") +
  ylab("Prices") +
  labs(title = "Summary of Prices in Different Categories of Shoes") +
  theme(plot.title = element_text(hjust = 0))+
  theme_classic()
ggplotly(tmp2)

The summary above shows the average price of most of categories are way lower than the median. So we decided to deep into the average price which are under $200 in order to see what the data can tell us about. As the boxplot shows that the the most price distribution are below $100, we decided to choose the sample of price less than 100 to do the further analysis.

new_df2 %>% 
  filter(category != "others", prices < 200) %>% 
  ggplot(aes(x = category, y = prices))+
  geom_boxplot(color = "#7C7F91")+
  theme_classic()+
  labs(title = "Price Among Categories") ->price_category
ggplotly(price_category)

Here is the comparision among different categories, avg_price and count. We was planning to choose the top two of highest count categories to see the price trend over the past 4 years. But we found that there are missing data for both sandal and flat before 2016. Therefore, we chose to compare the price trend for both boots and pump.

tmp1 <- avg_price_category %>% 
  filter(category != "others") %>% 
  ggplot(aes(x = category, y = avg_price_by_category, size = count)) +
  geom_point(color = "darkseagreen3") +
  theme_bw() +
  xlab("Category of Shoes") +
  ylab("Average Price in Each Category") +
  labs(title = "The Count of Average Price in Different Categories") +
  theme(plot.title = element_text(hjust = 0))
  
ggplotly(tmp1)

In order to see the price trend over the past 4 years, we format the date coloum to year and month, and also we computed the average price based on category and seperately filter both boots and pump category as our oberservations. In the end, we plot two lines for both category in one gragh in order to compare the price trend from time to time. As a result, we can see that the average price for pump shoes is steadily increase, and the average price for boots had a significant increase from December, 2015 to October, 2016 and them drop significantly after that until July, 2017. Overall, we can see the average price for boots is more fluctuating while pumps shoes is more stable.

format(new_df2$dateAdded, "%Y-%m") -> new_df2$dateAdded
new_df2 %>% 
  group_by(dateAdded, category) %>% 
  summarize(
    avgprice_by_ym = mean(prices)
  ) %>% 
  arrange(dateAdded) -> avgprice_by_ym
avgprice_by_ym %>% 
  filter(category =="boots") ->boots
avgprice_by_ym %>% 
  filter(category =="pump") ->pump
p = ggplot() +
  geom_line(data = boots, aes(x = dateAdded, y = avgprice_by_ym, color = category, group = 1))+
   geom_line(data =pump, aes(x = dateAdded, y = avgprice_by_ym, color = category, group = 1))+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 90, hjust = 1))+
  labs(title = "Trend of Avg.Price in Both Boots and Pump")+
  xlab("Year-Month")+
  ylab("Average Price")
ggplotly(p)

Price Inspection on Brand

First, we create a copy of dataframe from the previous part.

shoes_price <- new_df2
glimpse(shoes_price)
Observations: 9,691
Variables: 7
Groups: id [8,643]
$ id        <chr> "AWpIeaEfM263mwCq78AC", "AWoxI9NHAGTnQPR7qqIT", "AWpx5SOVAGTnQPR7v…
$ dateAdded <chr> "2019-04", "2019-04", "2019-05", "2019-04", "2019-04", "2017-01", …
$ brand     <chr> "ugg", "asics", "easy street", "aerosoles", "lifestride", "easy st…
$ lowname   <chr> "ugg bailey bow tall ii women's shoes boots 1016434 black", "asics…
$ prices    <dbl> 383.26, 374.17, 346.65, 346.65, 346.65, 346.65, 346.65, 338.95, 31…
$ category  <chr> "boots", "others", "boots", "boots", "flat", "sandal", "sandal", "…
$ discount  <chr> "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", …

Top 3 brands

To get a snippet of the popular price range among popular shoe brands, we choose the top 3 brands (Brinley Co., SAS, and Trotters) and create a combined density plot (as an alternative of histograms) with vertical lines representing the brand means.

top3 <- top_brand[1:3, ]
shoes_price %>%
 semi_join(top3, by = "brand") -> sampleBrand
ggdensity(sampleBrand, x = "prices", y = "..count..", rug = TRUE,
   add = "mean",
   add.params = list(color = c("#7C7F91", "#CDBCB6", "#FDDDAA"), linetype = "longdash", size = 1),
   color = "brand", fill = "brand",
   palette = c("#ADDED4", "#B5D4E9", "#DBBDE5"),
   xlab = "Price", ylab = "Number of shoes",
   title = "Price distribution of sample brands",
   legend = "right") 

First, we would like to inspect the trends individually. The distributions of Brinley Co. and SAS are right-skewed, which is the effect out high value shoes. Trotters displays a relatively “binomial” distribution, because the prices tend to diverge to the edges instead of merging at the center. Then we observe two overlapping areas: one is [40, 60] and the other is [110, 160].

We can define these two ranges as the “popular” ones based on the sample properties. Top 3 brands cover nearly 20% ((1002 + 455 + 451)/9709) of the shoes. Such portion of the data size can somehow reflect the retailer’s favor. Another interesting pattern in this sample is the relative location of price statistics (mean). Brinley Co. and SAS have extreme mean values (as we have mentioned in the box plot). Trotters has a mean of $83, pretty close to the overall mean. This pattern makes the 3-observation sample quite representative; along with their popularities, we can conclude that the overlapped ranges are reliable to suggest the popular ranges.

Overall Trend

At the end of the price inspection, we plot a density graph for all shoe prices regardless of their categories and brands:

dist_all <- ggdensity(shoes_price, x = "prices", y = "..count..",rug = TRUE, 
          fill = "#ADDED4", color = "#ADDED4", alpha = 0.7,
          add = "mean", 
          add.params = list(color = "#7C7F91", linetype = "longdash", size = 1),
          xlab = "Average Price", ylab = "Number of shoes",
          main = "Price distribution of shoes") + 
  coord_cartesian(xlim = c(0, 300)) + 
  theme_classic()
Using both `xintercept` and `mapping` may not have the desired result as mapping is overwritten if `xintercept` is specified
ggplotly(dist_all) %>% 
  layout(title = list(text = paste0("Price distribution of shoes",
                                    "<br>",
                                    "</sup>")))

The overall trend is right-skewed, even after we have removed outliers ($500 and above). As we have observed in the category box plot, most prices fall below $100. So if we set $100 as an upper bound to our data pool, the overall distribution would look more “normal”, which corresponds the statistical lemma that a larger sample size (compared to single brand trend) tends to display a more “Normal” distribution. Moreover, there are two density peaks, [45, 60] and [120, 150], which also overlaps with the popular range of Top 3 brands. Hence we can consider these ranges as “popular” to retailers.


Conclusions

We have analyzed a sample of ~9,700 of online women’s shoes listings and came to conclusion that most brands tend to offer more low prices shoes rather than high prices ones. Although some brands offer expensive shoes, they also have cheap options. This observation indicates that brands tend to target low to medium level income audience by offering “affordable prices”.

We have also identified the price distributions in category and brand. The general distribution pattern is right-skewed. In terms of popular prices, brands usually keep their price interval less than $350. We have also observed that the larger sample size tends to employ a more “Normal” distribution.

In addition, we have noticed some categorical trends. Black, white, shades and beige shoes keep earning favors in different seasons. Size 7 and 8 have a larger potential customer group. Most manufactures tend to launch new products in April and September. All these trends could reflect shoe industry’s preference from 2015 to 2019, and fashion analysts could predict future trends with more research.

Based on the summary, we would be able to provide some recommendations to those who are referring to Women's Shoes dataset. When purchasing products, retailers could focus more on black and white shoes, or other color tones in response to season change. They may also need to identify target groups of customers first to set price for shoes. Two frequent ranges, $45 - $60 and $120 - $150, can be references on customer’s preference based on different types of shoes.

LS0tCnRpdGxlOiAiVGVhbSA3IFN1bW1hcnkgUmVwb3J0IC0gV29tZW4ncyBTaG9lcyBEYXRhc2V0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMjICpUZWFtIG1lbWJlcnM6IENoZW5yYW4gUGVuZywgUWlhb2xpbmcgSHVhbmcsIFNoaWhhbiBMaSwgWmlxaW4gTWEsIEVsbWlyYSBVc2hpcm92YSoKCiMjIEludHJvZHVjdGlvbgpUaGUgW2RhdGFzZXRdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YWZpbml0aS93b21lbnMtc2hvZXMtcHJpY2VzI0RhdGFmaW5pdGlfV29tZW5zX1Nob2VzX0p1bjE5LmNzdikgdGhhdCB3ZSBhcmUgdXNpbmcgZm9yIHRoaXMgcHJvamVjdCBpcyBzYW1wbGVkIGZyb20gYSBsYXJnZSBkYXRhc2V0IG9mIGBXb21lbidzIFNob2VzYCBmcm9tIERhdGFmaW5pdGkgZGF0YWJhc2UuIEl0IGNvbnRhaW5zIGFyb3VuZCAxMCwwMDAgb25saW5lIHdvbWVuIHNob2VzIGxpc3RpbmdzIGZyb20gQXByaWwgMjAxNSB0byBBcHJpbCAyMDE5ICg5LDcwOSBhZnRlciBkYXRhIGNsZWFuaW5nKS4gVGhlIGRhdGFzZXQgaGFzIDMyIGNvbHVtbnMgYW5kIGluY2x1ZGVzIGluZm9ybWF0aW9uIHN1Y2ggYXMgYG5hbWVgLCBgYnJhbmRgLCBtaW5pbXVtIGFuZCBtYXhpbXVtIGBwcmljZXNgLCBgc2l6ZWAsIGBjb2xvcmAsIHVybCBsaW5rcyBhbmQgYWRkaXRpb25hbHMgZm9yIGVhY2ggb2ZmZXJlZCBwYWlyIG9mIHdvbWVuIHNob2VzLiBGb3IgdGhlIHB1cnBvc2VzIG9mIG91ciBhbmFseXNpcywgd2UgZGVjaWRlZCB0byBmb2N1cyBtYWlubHkgb24gc29tZSBjb2x1bW5zIGluY2x1ZGluZyBgZGF0ZWAsIGBwcmljZWAsIGBicmFuZHNgLCBgY29sb3JzYCwgYG5hbWVgIGFuZCBgc2l6ZWAuCgpCeSBhbmFseXppbmcgdGhpcyBkYXRhc2V0LCB3ZSB3b3VsZCBsaWtlIHRvIGlkZW50aWZ5IHdoYXQgdHJlbmRzIHRoZSBzaG9lcyBtYW51ZmFjdHVyZXJzIGZvbGxvdyBub3dhZGF5cyBhbmQgd2hhdCBraW5kIG9mIHByaWNpbmcgc3RyYXRlZ2llcyBzaG9lIGJyYW5kcyBoYXZlIG5vdy4gT3VyIGV4cGVjdGF0aW9uIGlzIHRvIGFuYWx5emUgdGhlIGRhdGEgaW4gZGlmZmVyZW50IGRpbWVuc2lvbnMgYW5kIGdpdmUgY29uY2x1c2lvbnMgYW5kIHJlY29tbWVuZGF0aW9ucyBvbiBzaG9lIHRyZW5kcyBieSBhbnN3ZXJpbmcgdGhlc2UgcXVlc3Rpb25zOgoKMS4gU2l6ZQorIE1vc3QgcG9wdWxhciBzaXplcyBmb3Igc2hvZXMgb24gc2FsZTsKMi4gQ29sb3IKKyBQb3B1bGFyIGNvbG9ycyBhbW9uZyBzaG9lczsKKyBQb3B1bGFyIGNvbG9ycyBpbiBlYWNoIHNlYXNvbjsKMy4gVGltZQorIFdoZW4gZG9lcyByZXRhaWxlcnMgdXN1YWxseSByZWxlYXNlIG5ldyBzaG9lczsKNC4gUHJpY2UKKyBCcmFuZHMgd2l0aCB3aWRlc3QgcHJpY2UgZGlzdHJpYnV0aW9uOworIFByaWNlIGluc3BlY3Rpb24gb24gY2F0ZWdvcmllczsKKyBQcmljZSBpbnNwZWN0aW9uIG9uIGJyYW5kcwoKLS0tLS0tLS0KCiMjIEdldCBzdGFydGVkOiBEYXRhIGNsZWFuaW5nCkluIHRoaXMgcHJvamVjdCwgd2UgdXNlIHRoZSBzYW1lIGRhdGFzZXQgYXMgdGhlIEJBIDc3MCBvbmUsIGFuZCB3ZSBoYXZlIGtub3duIHRoYXQgdGhlcmUgYXJlIG91dGxpZXJzLiBUbyBkbyBhIG1vcmUgc3lzdGVtYXRpYyBhbmFseXNpcywgd2Ugc3RhcnQgd2l0aCBkYXRhIGNsZWFuaW5nIGFuZCBvcmdhbml6aW5nLiAKCiMjIyBTdGVwIDE6IExvYWQgcGFja2FnZXMKYGBge3J9IAppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3RseSIpCmluc3RhbGwucGFja2FnZXMoImdndGhlbWVzIikKaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIikKaW5zdGFsbC5wYWNrYWdlcygiZ2dwdWJyIikKIyBjb21tYW5kcyBhYm92ZSBjYW4gYmUgc2tpcHBlZCBpZiB0aGVzZSBoYXZlIGFscmVhZHkgYmVlbiBpbnN0YWxsZWQgb24gY3VycmVudCB3b3JraW5nIGVudmlyb25tZW50CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShnZ3B1YnIpCndvbWVuX3Nob2VzIDwtIEZpbmFsX3ZlcnNpb25fRmluYWxfdmVyc2lvbl8zXwpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKYGBgCkNoZWNrIGZvciB0aGUgdW5pcXVlIG51bWJlciBvZiBicmFuZHMgKGJlZm9yZSBjbGVhbmluZyk6CmBgYHtyfQpsZW5ndGgodW5pcXVlKHdvbWVuX3Nob2VzJGJyYW5kKSkKYGBgCiMjIyBTdGVwIDI6IENsZWFuIHNwZWNpYWwgc3ltYm9scyBpbiBgYnJhbmRgIGFuZCBkcm9wIGFsbCBOQXMKYGBge3J9CndvbWVuX3Nob2VzIDwtIGRyb3BfbmEod29tZW5fc2hvZXMpCndvbWVuX3Nob2VzJGJyYW5kIDwtIHRvbG93ZXIod29tZW5fc2hvZXMkYnJhbmQpCndvbWVuX3Nob2VzJGJyYW5kIDwtIGdzdWIoIi0iLCIgIix3b21lbl9zaG9lcyRicmFuZCkKZm9yIChpIGluIDE6IG5yb3cod29tZW5fc2hvZXMpKSB7CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJhZW9yb3NvbGVzIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImFlcm9zb2xlcyIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJiYW1ib28gQnJhbmQiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImJhbWJvbyIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICAiYmFyZXRyYXBzIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImJhcmUgdHJhcHMiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAiYmVhY29uIiApIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtICJiZWFjb24gc2hvZXMiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAiYmVuamFtaW4gd2FsayIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAiYmVuamFtaW4gd2FsayBkeWVhYmxlcyIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJjYXJsb3MgYnkgY2FybG8gc2FudGFuYSIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAiY2FybG9zIgogIH0gZWxzZSBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImNhcmxvcyBieSBjYXJsb3Mgc2FudGFuYSIpIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtICJjYXJsb3MiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAiY2F0IGZvb3R3ZWFyIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImNhdCIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJjaGFybGVzIGJ5IGNoYXJsZXMgZGF2aWQiKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAiY2hhcmxlcyBkYXZpZCIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJjaXR5Y2xhc3NpZmllZCIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAiY2l0eSBjbGFzc2lmaWVkIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImRpYmEiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImRpYmEgdHJ1ZSIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJkci4gc2Nob2xsJ3Mgc2hvZXMiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImRyLiBzY2hvbGwncyIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJkcmV3IHNob2UiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImRyZXciCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAgImVsbGllIHNob2VzIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImVsbGllIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImZlcmdpZSBmb290d2VhciIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAiZmVyZ2llIgogIH0gZWxzZSBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImZlcmdpZSBzaG9lcyIpIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtICJmZXJnaWUiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAgImdlbnVpbmUgZ3JpcCBmb290d2VhciIpIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtICJnZW51aW5lIGdyaXAiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAiai5yZW5lIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImouIHJlbmVlIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImpidSBieSBqYW1idSIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAiamJ1IgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gICJrb29sYWJ1cnJhIGJ5IHVnZyIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAia29vbGFidXJyYSIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJsJ2FydGlzdGUgYnkgc3ByaW5nIHN0ZXAiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImxhcnRpc3RlIgogIH0gZWxzZSBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImxhcnRpc3RlIGJ5IHNwcmluZyBzdGVwIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gImxhcnRpc3RlIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImxhdXJlbiBieSByYWxwaCBsYXVyZW4iICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gInJhbHBoIGxhdXJlbiIKICB9IGVsc2UgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICAibGF1cmVuIHJhbHBoIGxhdXJlbiIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAicmFscGggbGF1cmVuIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gImxpZmUgc3RyaWRlIiApIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtICJsaWZlc3RyaWRlIgogIH0gZWxzZSBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gICAibGlmZXN0cmlkZSBzaG9lcyIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAibGlmZXN0cmlkZSIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJtaWNoYWVsIG1pY2hhZWwga29ycyIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAibWljaGFlbCBrb3JzIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gInBsZWFzZXJ1c2EiICApIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtICJwbGVhc2VyIHVzYSIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICJza2VjaGVycyB3b3JrIikgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gInNrZWNoZXJzIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gICJzb2RhIHNob2VzIiAgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSJzb2RhIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gICAic29mdCBzdHlsZSBieSBodXNoIHB1cHBpZXMiICApIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtInNvZnQgc3R5bGUiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAic29mdHdhbGsgZm9vdHdlYXIiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0ic29mdHdhbGsiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAgInNvcmVsIGZvb3R3ZWFyIiApIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtInNvcmVsIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gICJzcGVycnkgdG9wICBzaWRlciIgICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gInNwZXJyeSB0b3Agc2lkZXIiCiAgfSBlbHNlIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAgInNwZXJyeSIgKSB7CiAgICB3b21lbl9zaG9lcyRicmFuZFtpXSA8LSAic3BlcnJ5IHRvcCBzaWRlciIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICAic3VtbWl0ZmFzaGlvbnMiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0ic3VtbWl0IGZhc2hpb25zIgogIH0KICBpZiAod29tZW5fc2hvZXMkYnJhbmRbaV0gPT0gICAidG9tcyBzaG9lcyIgICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gInRvbXMiCiAgfQogIGlmICh3b21lbl9zaG9lcyRicmFuZFtpXSA9PSAgInVnZyBhdXN0cmFsaWEiICApIHsKICAgIHdvbWVuX3Nob2VzJGJyYW5kW2ldIDwtInVnZyIKICB9CiAgaWYgKHdvbWVuX3Nob2VzJGJyYW5kW2ldID09ICAidmlvbmljIHdpdGggb3J0aGFoZWVsIHRlY2hub2xvZ3kiICkgewogICAgd29tZW5fc2hvZXMkYnJhbmRbaV0gPC0gInZpb25pYyIKICB9Cn0KCmxlbmd0aCh1bmlxdWUod29tZW5fc2hvZXMkYnJhbmQpKQpnbGltcHNlKHdvbWVuX3Nob2VzKQpgYGAKCi0tLS0tLS0tCiMjIDEuIFNpemUKIyMjIE1vc3QgcG9wdWxhciBzaXplcyBmb3Igc2hvZXMgb24gc2FsZQpgYGB7cn0Kd29tZW5fc2hvZXMgJT4lCiBncm91cF9ieShzaXplcykgJT4lCiBtdXRhdGUoCiAgIGRpc2NvdW50ID0gY2FzZV93aGVuKAogICAgIHN0cl9kZXRlY3QocHJpY2VzLm9mZmVyLCBwYXR0ZXJuID0gIm9mZiIpIH4gIlllcyIsCiAgICAgVFJVRSB+ICJObyIKICkKICkgJT4lCiBmaWx0ZXIoZGlzY291bnQgPT0gIlllcyIpICU+JQogc3VtbWFyaXplKAogICAgIGNvdW50ID0gbigpCiAgICkgJT4lCiBzZWxlY3Qoc2l6ZXMsIGNvdW50KSAlPiUKIGFycmFuZ2UoZGVzYyhjb3VudCkpICU+JQogZmlsdGVyKHNpemVzICE9ICJtdWx0aXBsZSIpLT4gc2FsZQoKaGVhZChzYWxlKQpgYGAKV2UgY2FuIHNlZSBmcm9tIGNoYXJ0IGFib3ZlIHRoYXQgdGhlIG1vc3QgcG9wdWxhciBzaXplcyB3aGlsZSBvbiBzYWxlIGFyZSBzaXplICoqOCoqIGFuZCAqKjcqKi4KCi0tLS0tLS0tCiMjIDIuIENvbG9yCiMjIyBQb3B1bGFyIGNvbG9ycyBhbW9uZyBzaG9lcwpgYGB7cn0KSWRjb2xvcnMgPC0gdW5pcXVlKHdvbWVuX3Nob2VzJGNvbG9ycykKSWRjb2xvcnMgPC0gYXMuZGF0YS5mcmFtZShJZGNvbG9ycykKdGVtcCA8LSBzZXBhcmF0ZV9yb3dzKElkY29sb3JzLCBJZGNvbG9ycywgc2VwID0gIiwiKQpzdW1tYXJ5KHRlbXApCklkY29sIDwtIHVuaXF1ZSh0ZW1wKQpjbGFzcyhJZGNvbCkKc3VtbWFyeShJZGNvbCkKZm9yIChpIGluIDE6bnJvdyhJZGNvbCkpIHsKIElkY29sJGNvdW50W2ldIDwtIHN1bShzdHJfY291bnQod29tZW5fc2hvZXMkY29sb3JzLCBwYXR0ZXJuID0gSWRjb2wkSWRjb2xvcnNbaV0pLCBuYS5ybSA9IFRSVUUpCn0KSWRjb2wgPC0gYXJyYW5nZShJZGNvbCwgZGVzYyhjb3VudCkpCklkY29scGxvdCA8LSBoZWFkKElkY29sLCAxMCkgJT4lCiAgICAgICAgICAgIGZpbHRlcihJZGNvbG9ycyAhPSJUYSIsIElkY29sb3JzICE9IlBhdGVudCIgICkKcGN0IDwtIHJvdW5kKElkY29scGxvdCRjb3VudC9zdW0oSWRjb2xwbG90JGNvdW50KSoxMDApCmxibHMgPC0gcGFzdGUoSWRjb2xwbG90JElkY29sb3JzLCBwY3QpCmxibHMgPC0gcGFzdGUobGJscywiJSIsc2VwPSIiKQpwaWUocGN0LGxhYmVscyA9IGxibHMsIGNvbD1jKCIjQURERUQ0IiwiI0I1RDRFOSIsIiNDM0NFRDkiLCIjQzlFNEI0IiksCiAgIG1haW49IlBvcHVsYXIgY29sb3JzIGluIGdlbmVyYWwiKQpgYGAKCioqQmxhY2sqKiBhbmQgKip3aGl0ZSoqIHRha2Ugb3ZlciBhbG1vc3QgNjAlIGFtb25nIGFsbCBjb2xvcnMsIGFuZCBlYWNoIG9mIHRoZSByZXN0IGhhcyBsZXNzIHRoYW4gMTAlLgoKIyMjIFBvcHVsYXIgY29sb3JzIGluIGVhY2ggc2Vhc29uCldlIG1ha2UgYSBjb3B5IGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQgdG8gd29yayBvbi4KYGBge3J9CnNob2VzdyA8LSB3b21lbl9zaG9lcwpzdW1tYXJ5KHNob2VzdykKYGBgClRoZW4gd2UgY29uc3RydWN0IDQgZGlmZmVyZW50IGRhdGFmcmFtZXMgZm9yIGVhY2ggc2Vhc29uLgpgYGB7cn0Kc2hvZXN3ICU+JSAKICBtdXRhdGUoc2Vhc29uID1pZmVsc2UobW9udGgoZGF0ZUFkZGVkKSAlaW4lIGMoMSwyLDEyKSwgIldpbnRlciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1vbnRoKGRhdGVBZGRlZCkgJWluJSBjKDMsNCw1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNwcmluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtb250aChkYXRlQWRkZWQpICVpbiUgYyg2LDcsOCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3VtbWVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZhbGwiKSkpKSAtPiBzaG9lc3cKYGBgCkdsaW1wc2UgYXQgZGF0YSBmcmFtZSB3aXRoIG5ldyBjb2x1bW0uCmBgYHtyfQpnbGltcHNlKHNob2VzdykKYGBgCiMjIyMgLVdpbnRlciBjb2xvcjoKYGBge3J9CldpbnRlciA8LSBzaG9lc3cgJT4lIAogICAgICAgICAgZmlsdGVyKHNlYXNvbiA9PSAiV2ludGVyIikKV2NvbG9ycyA8LSB1bmlxdWUoV2ludGVyJGNvbG9ycykKV2NvbG9ycyA8LSBhcy5kYXRhLmZyYW1lKFdjb2xvcnMpCnRlbXAgPC0gc2VwYXJhdGVfcm93cyhXY29sb3JzLCBXY29sb3JzLCBzZXAgPSAiLCIpCnN1bW1hcnkodGVtcCkKV2NvbCA8LSB1bmlxdWUodGVtcCkKCgpmb3IgKGkgaW4gMTpucm93KFdjb2wpKSB7CiAgV2NvbCRjb3VudFtpXSA8LSBzdW0oc3RyX2NvdW50KFdpbnRlciRjb2xvcnMsIHBhdHRlcm4gPSBXY29sJFdjb2xvcnNbaV0pKQp9CgpXY29sIDwtIGFycmFuZ2UoV2NvbCwgZGVzYyhjb3VudCkpCldjb2xwbG90IDwtIGhlYWQoV2NvbCwgMTApCgogIGdncGxvdChkYXRhID0gV2NvbHBsb3QsIG1hcHBpbmcgPSBhZXMoeCA9IHJlb3JkZXIoV2NvbG9ycywgLWNvdW50KSwgeSA9IGNvdW50LCBmaWxsPSByZW9yZGVyKFdjb2xvcnMsIC1jb3VudCkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIldoaXRlIiA9ICJXaGl0ZSIsICJCbGFjayIgPSAiQmxhY2siLCAiQmx1ZSIgPSAiIzAwMDBGRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5hdnkiID0gIiMwMDAwODAiLCAiQm9uZSIgPSAiI2UzZGFjOSIsICJUdXJxdW8iID0gIiM0MEUwRDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcmV5IiA9ICIjODA4MDgwIiwgIkJlaWdlIiA9ICIjZjVmNWRjIiwgIk5hdHVyYWwiID0gIiNjYWE0NzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGV3dGVyIiA9ICIjOGU5Mjk0IikpICsKICBsYWJzKHggPSAiY29sb3JzIiwgeSA9ICJudW1iZXIgb2YgbGlzdGluZ3MiLCB0aXRsZSA9ICJQb3B1bGFyIGNvbG9ycyBpbiBXaW50ZXIiKSArICAKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQoKYGBgClRoZSBtb3N0IHBvcHVsYXIgY29sb3IgZHVyaW5nIFdpbnRlciBpcyAiV2hpdGUiIGFuZCDigJxCbGFja+KAnS4gTW9zdCBvZiB0aG9zZSBjb2xvcnMgYXJlIG9mIGNvbGRlciB0b25lcywgd2hpY2ggaXMgcXVpdGUgdW5kZXJzdGFuZGFibGUgY29uc2lkZXJpbmcgdGhhdCB3aW50ZXIgaXMgYSBjb2xkIHRpbWUgb2YgdGhlIHllYXIuCgojIyMjIC1GYWxsIGNvbG9yOgpgYGB7cn0KRmFsbCA8LSBzaG9lc3cgJT4lIAogICAgICAgICAgZmlsdGVyKHNlYXNvbiA9PSAiRmFsbCIpCkZjb2xvcnMgPC0gdW5pcXVlKEZhbGwkY29sb3JzKQpGY29sb3JzIDwtIGFzLmRhdGEuZnJhbWUoRmNvbG9ycykKdGVtcCA8LSBzZXBhcmF0ZV9yb3dzKEZjb2xvcnMsIEZjb2xvcnMsIHNlcCA9ICIsIikKc3VtbWFyeSh0ZW1wKQpGY29sIDwtIHVuaXF1ZSh0ZW1wKQpjbGFzcyhGY29sKQoKZm9yIChpIGluIDE6bnJvdyhGY29sKSkgewogIEZjb2wkY291bnRbaV0gPC0gc3VtKHN0cl9jb3VudChGYWxsJGNvbG9ycywgcGF0dGVybiA9IEZjb2wkRmNvbG9yc1tpXSkpCn0KCkZjb2wgPC0gYXJyYW5nZShGY29sLCBkZXNjKGNvdW50KSkKRmNvbHBsb3QgPC0gaGVhZChGY29sLCAxMSkgJT4lIAogICAgICAgICAgICBmaWx0ZXIoRmNvbG9ycyAhPSAiQWxsIEJsYWNrIikKCgpnZ3Bsb3QoZGF0YSA9IEZjb2xwbG90LCBtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKEZjb2xvcnMsIC1jb3VudCksIHkgPSBjb3VudCwgZmlsbCA9IHJlb3JkZXIoRmNvbG9ycywgLWNvdW50KSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkJsYWNrIiA9ICJCbGFjayIsICJTaWx2ZXIiID0gIiNDMEMwQzAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCcm93biIgPSAiI0E1MkEyQSIsICJXaGl0ZSIgPSAiV2hpdGUiLCAiVGFuIiA9ICIjRDJCNDhDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGF1cGUiID0gIiNiMzhiNmQiLCAiUGVyaXdpbmtsZSIgPSAiI0NDQ0NGRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaG9jb2xhdGUiID0gIiNEMjY5MUUiLCJDaW5uYW1vbiIgPSAiI2QyNjkxZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCbHVlIiA9IiMwMDAwRkYiKSkgKwogIGxhYnMoeCA9ICJjb2xvcnMiLCB5ID0gIm51bWJlciBvZiBsaXN0aW5ncyIsIHRpdGxlID0gIlBvcHVsYXIgY29sb3JzIGluIEZhbGwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKCmBgYApUaGUgbW9zdCBwb3B1bGFyIGNvbG9yIGZvciBGYWxsIHNlYXNvbiBpcyAiQmxhY2siLiBUaGUgY29sb3IgdG9uZXMgbG9vayBxdWl0ZSBzdWl0YWJsZSBmb3IgRmFsbCBzZWFzb24uIAoKIyMjIyAtU3VtbWVyIGNvbG9yOgpgYGB7cn0KU3VtbWVyIDwtIHNob2VzdyAlPiUgCiAgICAgICAgICAgZmlsdGVyKHNlYXNvbiA9PSAiU3VtbWVyIikKU3Vjb2xvcnMgPC0gdW5pcXVlKFN1bW1lciRjb2xvcnMpClN1Y29sb3JzIDwtIGFzLmRhdGEuZnJhbWUoU3Vjb2xvcnMpCnRlbXAgPC0gc2VwYXJhdGVfcm93cyhTdWNvbG9ycywgU3Vjb2xvcnMsIHNlcCA9ICIsIikKc3VtbWFyeSh0ZW1wKQpTdWNvbCA8LSB1bmlxdWUodGVtcCkKY2xhc3MoU3Vjb2wpCgpmb3IgKGkgaW4gMTpucm93KFN1Y29sKSkgewogIFN1Y29sJGNvdW50W2ldIDwtIHN1bShzdHJfY291bnQoU3VtbWVyJGNvbG9ycywgcGF0dGVybiA9IFN1Y29sJFN1Y29sb3JzW2ldKSkKfQoKU3Vjb2wgPC0gYXJyYW5nZShTdWNvbCwgZGVzYyhjb3VudCkpClN1Y29scGxvdCA8LSBoZWFkKFN1Y29sLCAxMCkgJT4lIAogICAgICAgICAgICAgZmlsdGVyKFN1Y29sb3JzICE9ICJCbGFjayAgTGVvcGFyZCIpCgpnZ3Bsb3QoZGF0YSA9IFN1Y29scGxvdCwgbWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihTdWNvbG9ycywgLWNvdW50KSwgeSA9IGNvdW50LCBmaWxsID0gcmVvcmRlcihTdWNvbG9ycywgLWNvdW50KSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQmxhY2siID0gIkJsYWNrIiwiQnJvd24iID0gIiNBNTJBMkEiLCAiRHVzdHkiID0gIiNhYzliOWIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMZW9wYXJkIiA9ICIjYTM3MzE5IiwgIldoaXRlIiA9ICJXaGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRhdXBlIiA9ICIjYjM4YjZkIiwgIkJsYWNrIFN1ZWRlIiA9ICIjM2QzZTNjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVpZ2UiID0gIiNmNWY1ZGMiLCAiRHVzdHkgQnJvd24gU3VlZGUiID0iI0ExN0Y3MiIpKSArCiAgbGFicyh4ID0gImNvbG9ycyIsIHkgPSAibnVtYmVyIG9mIGxpc3RpbmdzIiwgdGl0bGUgPSAiUG9wdWxhciBjb2xvcnMgaW4gU3VtbWVyIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCmBgYApUaGUgbW9zdCBwb3B1bGFyIGNvbG9yIGZvciBTdW1tZXIgc2Vhc29uIGlzIGFsc28gIkJsYWNrIi4gV2hpY2ggaXMgYSBsaXR0bGUgYml0IHN1cnByaXNpbmcsIGFzIHdlIHdvdWxkIGV4cGVjdCBtb3JlIGJyaWdodCBhbmQgcG9wcGluZyBjb2xvcnMgYmVpbmcgdGhlIG1vc3QgcG9wdWxhciBvbmVzIGR1cmluZyBTdW1tZXIgdGltZS4gTmV2ZXJ0aGVsZXNzLCAiQnJvd24iLCAiRHVzdHkiIGFuZCAiTGVvcGFyZCIgY29sb3JzIGFyZSBlcXVhbGx5IHBvcHVsYXIgZHVyaW5nIFN1bW1lci4gQXBwYXJlbnRseSwgIkxlb3BhcmQiIHByaW50IGlzIHZlcnkgcG9wdWxhciBkdXJpbmcgc3VtbWVyIHRpbWUuCgojIyMjIC1TcHJpbmcgY29sb3I6CmBgYHtyfQpTcHJpbmcgPC0gc2hvZXN3ICU+JSAKICAgICAgICAgICAgZmlsdGVyKHNlYXNvbiA9PSAiU3ByaW5nIikKU3Bjb2xvcnMgPC0gdW5pcXVlKFNwcmluZyRjb2xvcnMpClNwY29sb3JzIDwtIGFzLmRhdGEuZnJhbWUoU3Bjb2xvcnMpCnRtcCA8LSBzZXBhcmF0ZV9yb3dzKFNwY29sb3JzLCBTcGNvbG9ycywgc2VwID0gYygiLCIpKQpzdW1tYXJ5KHRtcCkKU3Bjb2wgPC0gdW5pcXVlKHRtcCkKY2xhc3MoU3Bjb2wpCgpmb3IgKGkgaW4gMTpucm93KFNwY29sKSkgewogIFNwY29sJGNvdW50W2ldIDwtIHN1bShzdHJfY291bnQoU3ByaW5nJGNvbG9ycywgcGF0dGVybiA9IFNwY29sJFNwY29sb3JzW2ldKSwgbmEucm0gPSBUUlVFKQp9CgpTcGNvbCA8LSBhcnJhbmdlKFNwY29sLCBkZXNjKGNvdW50KSkKU3Bjb2xwbG90IDwtIGhlYWQoU3Bjb2wsIDEwKSAlPiUgCiAgICAgICAgICAgICBmaWx0ZXIoU3Bjb2xvcnMgIT0gIlRhIiwgU3Bjb2xvcnMgIT0gIlBhdGVudCIpCgpnZ3Bsb3QoZGF0YSA9IFNwY29scGxvdCwgbWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihTcGNvbG9ycywgLWNvdW50KSwgeSA9IGNvdW50LCBmaWxsID0gcmVvcmRlcihTcGNvbG9ycywgLWNvdW50KSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQmxhY2siID0gIkJsYWNrIiwiV2hpdGUiID0gIldoaXRlIiwgIkdyZXkiID0gIiM4MDgwODAiLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJvd24iID0gIiNBNTJBMkEiLCAiUmVkIiA9ICIjRkYwMDAwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR29sZCIgPSAiI0ZGRDcwMCIsICJTaWx2ZXIiID0gIiNDMEMwQzAiLCJCZWlnZSIgPSAiI2Y1ZjVkYyIpKSsKICBsYWJzKHggPSAiY29sb3JzIiwgeSA9ICJudW1iZXIgb2YgbGlzdGluZ3MiLCB0aXRsZSA9ICJQb3B1bGFyIGNvbG9ycyBpbiBTcHJpbmciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKYGBgClRoZSBtb3N0IHBvcHVsYXIgY29sb3IgZm9yIFNwcmluZyBzZWFzb24gaXMgYWxzbyAiQmxhY2siLiBBbHNvIGhlcmUgd2Ugc2VlIG1vcmUgCgpDb25jbHVzaW9uOiBFeGNlcHQgZm9yIFdpbnRlciwgdGhlIG1vc3QgcG9wdWxhciBjb2xvciBpcyAqKkJsYWNrKiosIHdoaWNoIGlzIHF1aXRlIHVuZGVyc3RhbmRhYmxlIGFzIGJsYWNrIHNob2VzIGFyZSBjb25zaWRlcmVkIGFzIGEgY29tbW9uIG9wdGlvbiwgYmVjYXVzZSB0aGV5IHVzdWFsbHkgZml0IHdlbGwgd2l0aCBhbnkgb3RoZXIgY29sb3JzIGluIGEgd2hvbGUgb3V0Zml0LiBXaW50ZXIncyBwb3B1bGFyIGNvbG9yLCAqKldoaXRlKiosIGlzIGFsc28gdW5kZXJzdGFuZGFibGUgYXMgcGVvcGxlIG1heSB0ZW5kIHRvIG1hdGNoIHNub3cgY29sb3IgaW4gd2ludGVyLiBNb3Jlb3ZlciwgdGhlIHBvcHVsYXIgY29sb3JzIGluIHNlYXNvbnMgdGVuZCB0byBtYXRjaCB0aGUgdG9uZXMgb2YgdGhlIHNlYXNvbnMuIAoKLS0tLS0tCiMjIDMuIFRpbWUKIyMjIFdoZW4gZG9lcyByZXRhaWxlcnMgdXN1YWxseSByZWxlYXNlIG5ldyBzaG9lcwpgYGB7cn0Kd29tZW5fc2hvZXMkbW9udGggPC0gbW9udGhzKGFzLkRhdGUod29tZW5fc2hvZXMkZGF0ZUFkZGVkKSkKd29tZW5fc2hvZXMkeWVhciA8LSB5ZWFyKGFzLkRhdGUod29tZW5fc2hvZXMkZGF0ZUFkZGVkKSkKd29tZW5fc2hvZXMlPiUKICBmaWx0ZXIoeWVhciA9PSAiMjAxNSIpIC0+IG5ld19kYXRlCmdncGxvdChuZXdfZGF0ZSwgYWVzKHggPSBtb250aCkpICsgCiAgICBnZW9tX2JhcihzdGF0ID0gICJjb3VudCIsIG5hLnJtID0gVFJVRSwgZmlsbCA9ICJkYXJrc2VhZ3JlZW4zIikKYGBgCgpXZSBsaW1pdGVkIG91ciBkYXRhc2V0IHRvIG9ubHkgb25lIHllYXIgcmFuZ2UgYXMgb3VyIGRhdGFzZXQgaGF2ZSBzbyBtYW55IG1pc3NpbmcgZGF0YSwgZm9yIGV4YW1wbGUgd2Ugb25seSBoYXZlIGRhdGEgZm9yIEFwcmlsIGFuZCBNYXkgaW4gMjAxOS4gIEJhc2VkIG9uIHRoZSByZXN1bHQgd2UgY2FuIHNlZSB0aGF0ICoqQXByaWwqKiBhbmQgKipTZXB0ZW1iZXIqKiBhcmUgdGhlIG1vbnRoIHRoYXQgbW9zdCBicmFuZCBsYXVuY2ggdGhlaXIgbmV3IHByb2R1Y3QgZm9sbG93IGJ5IEF1Z3VzdCwgTm92ZW1iZXIgYW5kIERlY2VtYmVyLiBXZSBjYW4gYXNzdW1lIHRoYXQgbW9zdCBicmFuZCB1c3VhbGx5IHJlbGVhc2UgdGhlaXIgcHJvZHVjdHMgZm9yIGJldHdlZW4gdHdvIHNlYXNvbnMuIAoKLS0tLS0tLS0KIyMgNC4gUHJpY2UKIyMjIERhdGEgY2xlYW5pbmcgY29udGludWVkCkluIFByaWNlIHNlY3Rpb24sIHdlIG5lZWQgdG8gZnVydGhlciBjbGVhbiB0aGUgZGF0YXNldC4gV2Ugd291bGQgbGlrZSB0byBjaGFuZ2UgYWxsIHRoZSBsZXR0ZXJzIGluIGBuYW1lYCBpbnRvIGxvd2VyY2FzZSBhbmQgY3JlYXRlIGEgbmV3IGRhdGFmcmFtZSBjYWxsZWQgYG5ld19kZmAuCmBgYHtyfQp3b21lbl9zaG9lczIgPC0gdHJhbnNmb3JtKHdvbWVuX3Nob2VzLCBsb3duYW1lID0gdG9sb3dlcihuYW1lKSkKd29tZW5fc2hvZXMyICU+JSAKICBncm91cF9ieShpZCkgJT4lIAogIG11dGF0ZSgKICAgIHByaWNlcyA9IChwcmljZXMuYW1vdW50TWF4ICsgcHJpY2VzLmFtb3VudE1pbikvMgogICkgJT4lIAogIHNlbGVjdChpZCwgZGF0ZUFkZGVkLCBicmFuZCwgbG93bmFtZSwgcHJpY2VzLCBwcmljZXMub2ZmZXIpIC0+IG5ld19kZgpoZWFkKG5ld19kZikKYGBgClRoZW4gd2Ugd2FudCB0byBmaW5kIG91dGxpZXJzIHRocm91Z2ggYSBib3hwbG90IGdyYWdoLiBCYXNlZCBvbiB0aGUgcmVzdWx0LCB3ZSBjb25zaWRlciBwcmljZSBvdmVyIFwkNTAwIGFyZSBvdXRsaWVycy4KYGBge3J9CnRtcCA8LSBuZXdfZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IDEsIHkgPSBwcmljZXMpKSArCiAgZ2VvbV9ib3hwbG90KGNvbG9yID0gImJsYWNrIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpCmdncGxvdGx5KHRtcCkKYGBgCkEgbmV3IGJveHBsb3QgYWZ0ZXIgd2UgcmVtb3ZlIHRoZXNlIG91dGxpZXJzIChwcmljZXMgPiBcJDUwMCk6CmBgYHtyfQp0bXAwIDwtIG5ld19kZiAlPiUgCiAgZmlsdGVyKHByaWNlcyA8IDUwMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IDEsIHkgPSBwcmljZXMpKSArCiAgZ2VvbV9ib3hwbG90KGNvbG9yID0gImJsYWNrIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpCmdncGxvdGx5KHRtcDApCmBgYApOZXh0LCB3ZSBleGNsdWRlIG91dGxpZXJzIGFuZCBleHRyYWN0IHRoZSBwYXR0ZXJuIGZyb20gYG5hbWVgLiBXZSBhbHNvIGNyZWF0ZSBhIG5ldyBjb2x1bW4gYGNhdGVnb3J5YCBzcGVjaWZ5aW5nIGRpZmZlcmVudCBjYXRlZ29yaWVzIGZvciBlYWNoIHBhaXIgb2Ygc2hvZXMuIEZpbmFsbHksIHdlIGV4dHJhY3QgIm9mZiIgZnJvbSBgcHJpY2VzLm9mZmVyYCBhbmQgY3JlYXRlIGEgbmV3IGNvbHVtbiBgZGlzY291bnRgIHdoaWNoIGluZGljYXRlcyB3aGV0aGVyIHRoZSBwcmljZSBpcyBvbiBzYWxlIG9yIG5vdC4gCmBgYHtyfQp0ZXN0MSA8LSBuZXdfZGYgJT4lIAogIG11dGF0ZSgKICAgIGNhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KGxvd25hbWUsIHBhdHRlcm4gPSAiYm9vdCIpIH4gImJvb3RzIiwKICAgICAgc3RyX2RldGVjdChsb3duYW1lLCBwYXR0ZXJuID0gInB1bXAiKSB+ICJwdW1wIiwKICAgICAgc3RyX2RldGVjdChsb3duYW1lLCBwYXR0ZXJuID0gICJzbmVha2VyIikgfiAic25lYWtlciIsCiAgICAgIHN0cl9kZXRlY3QobG93bmFtZSwgcGF0dGVybiA9ICJzYW5kYWwiKSB+ICJzYW5kYWwiLAogICAgICBzdHJfZGV0ZWN0KGxvd25hbWUsIHBhdHRlcm4gPSAiZmxhdCIpIH4gImZsYXQiLAogICAgICBzdHJfZGV0ZWN0KGxvd25hbWUsIHBhdHRlcm4gPSAic2xpcHBlciIpIH4gInNsaXBwZXIiLAogICAgICBzdHJfZGV0ZWN0KGxvd25hbWUsIHBhdHRlcm4gPSAibG9hZmVyIikgfiAibG9hZmVyIiwKICAgICAgc3RyX2RldGVjdChsb3duYW1lLCBwYXR0ZXJuID0gImNsb2ciKSB+ICJjbG9nIgogICAgKSwKICAgIGRpc2NvdW50ID0gY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KHByaWNlcy5vZmZlciwgcGF0dGVybiA9ICJvZmYiKSB+ICJZZXMiLAogICAgICBUUlVFIH4gIk5vIgogICAgKSAKICApICU+JSAKICBmaWx0ZXIocHJpY2VzIDwgNTAwKQoKdGVzdDEkY2F0ZWdvcnlbaXMubmEodGVzdDEkY2F0ZWdvcnkpXSA8LSAib3RoZXJzIgoKdGVzdDEgJT4lIApzZWxlY3QoaWQsIGRhdGVBZGRlZCwgYnJhbmQsIGxvd25hbWUsIHByaWNlcywgY2F0ZWdvcnksIGRpc2NvdW50KSAlPiUgCmFycmFuZ2UoZGVzYyhwcmljZXMpKS0+IG5ld19kZjIKaGVhZChuZXdfZGYyKQpgYGAKCiMjIyBCcmFuZHMgd2l0aCB3aWRlc3QgcHJpY2UgZGlzdHJpYnV0aW9uCmBgYHtyfQpzdW1tYXJ5KHdvbWVuX3Nob2VzKQpnbGltcHNlKG5ld19kZjIpCmBgYAoKYGBge3J9Cm5ld19kZjIgJT4lCiAgZ3JvdXBfYnkoYnJhbmQpICU+JQogIHN1bW1hcml6ZShwcmljZV9yYW5nZT0obWF4KGFzLm51bWVyaWMocHJpY2VzKSktbWluKGFzLm51bWVyaWMocHJpY2VzKSkpLAogICAgICAgICAgICBjb3VudCA9IG4oKSkgJT4lCiAgc2VsZWN0KGJyYW5kLCBjb3VudCwgcHJpY2VfcmFuZ2UpICU+JQogIGFycmFuZ2UoZGVzYyhwcmljZV9yYW5nZSkpIC0+IGRmMQpoZWFkKGRmMSwxMCkKYGBgCkxhc3QgdGltZSB3ZSBoYXZlIHNvbWUgYnJhbmQgdGhhdCBoYXZlIHByaWNlIHJhbmdlIGZvciBhcm91bmQgXCQ1MDAwLCBieSB3b3JraW5nIG1vcmUgb24gdGhpcyBkYXRhc2V0LCB3ZSBmaW5kIG91dCB0aGF0IHRoZXJlIGFyZSBzb21lIHByb2R1Y3Qgc2VsbCBmb3IgXCQ1MDAwLiBXZSBkaWQgc29tZSBkYXRhIGNsZWFuaW5nIG9uIHRoaXMgZGF0YXNldCB0byBnZXQgcmlkIG9mIHRob3NlIG91dGxpZXJzLiBBZnRlciBkb25lIHdpdGggdGhlIGRhdGEgY2xlYW5pbmcsIHdlIGdvdCBvdXIgcmVzdWx0IGZvciBwcmljZSBkaXN0cmlidXRpb24gb2YgZWFjaCBicmFuZC4gSGVyZSBhcmUgdG9wIDEwIGJyYW5kIHRoYXQgaGF2ZSB0aGUgd2lkZXN0IHByaWNlIGRpc3RyaWJ1dGlvbiByYW5nZS4gV2UgY2FuIHNlZSB0aGF0IGJyYW5kcyB1c3VhbGx5IGhhdmUgcHJpY2UgcmFuZ2Ugc21hbGxlciB0aGFuIFwkMzUwLgoKIyMjIFByaWNlIGluc3BlY3Rpb24gb24gY2F0ZWdvcmllcwpXZSBvYnNlcnZlIHRoYXQgYm9vdHMgaGFiZSB0aGUgaGlnaGVzdCBjb3VudCBhbmQgdGhlIGF2ZXJhZ2UgcHJpY2UgaXMgXCQ2Ny4gU2FuZGFscyBoYXZlIHRoZSBzZWNvbmQgaGlnaGVzdCBjb3VudCBhbmQgdGhlIGF2ZXJhZ2UgcHJpY2UgaXMgXCQ1Ny4gTW9yZSBhdmVyYWdlIHByaWNlcyBhcmUgc2hvd25lZCBhcyBiZWxvdzoKYGBge3J9Cm5ld19kZjIgJT4lIAogIGdyb3VwX2J5KGNhdGVnb3J5KSAlPiUgCiAgc3VtbWFyaXplKAogICAgYXZnX3ByaWNlX2J5X2NhdGVnb3J5ID0gbWVhbihwcmljZXMsIG5hLnJtID0gVFJVRSksCiAgICBjb3VudD0gbigpCiAgKSAlPiUgCiAgc2VsZWN0KGNhdGVnb3J5LCBjb3VudCwgYXZnX3ByaWNlX2J5X2NhdGVnb3J5KSAlPiUgCiAgYXJyYW5nZShhdmdfcHJpY2VfYnlfY2F0ZWdvcnkpLT4gYXZnX3ByaWNlX2NhdGVnb3J5CmhlYWQoYXZnX3ByaWNlX2NhdGVnb3J5LCA5KQpgYGAKV2UgbWFrZSBhIHN1bW1hcnkgb2YgcHJpY2VzIGluIGRpZmZlcmVudCBjYXRlZ29yaWVzLCBhbmQgc3VycHJpc2VseSBzZWUgdGhhdCB0aGUgYXZlcmFnZSBwcmljZSBpbiBhbGwgY2F0ZWdvcmllcyBhcmUgYmVsb3cgXCQxMDAuIApgYGB7cn0KdG1wMiA8LSBuZXdfZGYyICU+JSAKICBmaWx0ZXIoY2F0ZWdvcnkgIT0gIm90aGVycyIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjYXRlZ29yeSwgeSA9IHByaWNlcykpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSAibWVhbiIsIGZ1bi55bWluID0gbWluLCBmdW4ueW1heCA9IG1heCwgY29sb3VyID0gIiM3QzdGOTEiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSsKICB4bGFiKCJDYXRlZ29yeSBvZiBTaG9lcyIpICsKICB5bGFiKCJQcmljZXMiKSArCiAgbGFicyh0aXRsZSA9ICJTdW1tYXJ5IG9mIFByaWNlcyBpbiBEaWZmZXJlbnQgQ2F0ZWdvcmllcyBvZiBTaG9lcyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCkpKwogIHRoZW1lX2NsYXNzaWMoKQoKZ2dwbG90bHkodG1wMikKYGBgClRoZSBzdW1tYXJ5IGFib3ZlIHNob3dzIHRoZSBhdmVyYWdlIHByaWNlIG9mIG1vc3Qgb2YgY2F0ZWdvcmllcyBhcmUgd2F5IGxvd2VyIHRoYW4gdGhlIG1lZGlhbi4gU28gd2UgZGVjaWRlZCB0byBkZWVwIGludG8gdGhlIGF2ZXJhZ2UgcHJpY2Ugd2hpY2ggYXJlIHVuZGVyIFwkMjAwIGluIG9yZGVyIHRvIHNlZSB3aGF0IHRoZSBkYXRhIGNhbiB0ZWxsIHVzIGFib3V0LiBBcyB0aGUgYm94cGxvdCBzaG93cyB0aGF0IHRoZSB0aGUgbW9zdCBwcmljZSBkaXN0cmlidXRpb24gYXJlICoqYmVsb3cgXCQxMDAqKiwgd2UgZGVjaWRlZCB0byBjaG9vc2UgdGhlIHNhbXBsZSBvZiBwcmljZSBsZXNzIHRoYW4gMTAwIHRvIGRvIHRoZSBmdXJ0aGVyIGFuYWx5c2lzLiAKYGBge3J9Cm5ld19kZjIgJT4lIAogIGZpbHRlcihjYXRlZ29yeSAhPSAib3RoZXJzIiwgcHJpY2VzIDwgMjAwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY2F0ZWdvcnksIHkgPSBwcmljZXMpKSsKICBnZW9tX2JveHBsb3QoY29sb3IgPSAiIzdDN0Y5MSIpKwogIHRoZW1lX2NsYXNzaWMoKSsKICBsYWJzKHRpdGxlID0gIlByaWNlIEFtb25nIENhdGVnb3JpZXMiKSAtPnByaWNlX2NhdGVnb3J5CmdncGxvdGx5KHByaWNlX2NhdGVnb3J5KQpgYGAKSGVyZSBpcyB0aGUgY29tcGFyaXNpb24gYW1vbmcgZGlmZmVyZW50IGNhdGVnb3JpZXMsIGBhdmdfcHJpY2VgIGFuZCBjb3VudC4gV2Ugd2FzIHBsYW5uaW5nIHRvIGNob29zZSB0aGUgdG9wIHR3byBvZiBoaWdoZXN0IGNvdW50IGNhdGVnb3JpZXMgdG8gc2VlIHRoZSBwcmljZSB0cmVuZCBvdmVyIHRoZSBwYXN0IDQgeWVhcnMuIEJ1dCB3ZSBmb3VuZCB0aGF0IHRoZXJlIGFyZSBtaXNzaW5nIGRhdGEgZm9yIGJvdGggc2FuZGFsIGFuZCBmbGF0IGJlZm9yZSAyMDE2LiBUaGVyZWZvcmUsIHdlIGNob3NlIHRvIGNvbXBhcmUgdGhlIHByaWNlIHRyZW5kIGZvciBib3RoIGJvb3RzIGFuZCBwdW1wLiAKYGBge3J9CnRtcDEgPC0gYXZnX3ByaWNlX2NhdGVnb3J5ICU+JSAKICBmaWx0ZXIoY2F0ZWdvcnkgIT0gIm90aGVycyIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjYXRlZ29yeSwgeSA9IGF2Z19wcmljZV9ieV9jYXRlZ29yeSwgc2l6ZSA9IGNvdW50KSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya3NlYWdyZWVuMyIpICsKICB0aGVtZV9idygpICsKICB4bGFiKCJDYXRlZ29yeSBvZiBTaG9lcyIpICsKICB5bGFiKCJBdmVyYWdlIFByaWNlIGluIEVhY2ggQ2F0ZWdvcnkiKSArCiAgbGFicyh0aXRsZSA9ICJUaGUgQ291bnQgb2YgQXZlcmFnZSBQcmljZSBpbiBEaWZmZXJlbnQgQ2F0ZWdvcmllcyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCkpCiAgCmdncGxvdGx5KHRtcDEpCmBgYApJbiBvcmRlciB0byBzZWUgdGhlIHByaWNlIHRyZW5kIG92ZXIgdGhlIHBhc3QgNCB5ZWFycywgd2UgZm9ybWF0IHRoZSBkYXRlIGNvbG91bSB0byB5ZWFyIGFuZCBtb250aCwgYW5kIGFsc28gd2UgY29tcHV0ZWQgdGhlIGF2ZXJhZ2UgcHJpY2UgYmFzZWQgb24gY2F0ZWdvcnkgYW5kIHNlcGVyYXRlbHkgZmlsdGVyIGJvdGggYm9vdHMgYW5kIHB1bXAgY2F0ZWdvcnkgYXMgb3VyIG9iZXJzZXJ2YXRpb25zLiBJbiB0aGUgZW5kLCB3ZSBwbG90IHR3byBsaW5lcyBmb3IgYm90aCBjYXRlZ29yeSBpbiBvbmUgZ3JhZ2ggaW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgcHJpY2UgdHJlbmQgZnJvbSB0aW1lIHRvIHRpbWUuIEFzIGEgcmVzdWx0LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGF2ZXJhZ2UgcHJpY2UgZm9yIHB1bXAgc2hvZXMgaXMgc3RlYWRpbHkgaW5jcmVhc2UsIGFuZCB0aGUgYXZlcmFnZSBwcmljZSBmb3IgYm9vdHMgaGFkIGEgc2lnbmlmaWNhbnQgaW5jcmVhc2UgZnJvbSBEZWNlbWJlciwgMjAxNSB0byBPY3RvYmVyLCAyMDE2IGFuZCB0aGVtIGRyb3Agc2lnbmlmaWNhbnRseSBhZnRlciB0aGF0IHVudGlsIEp1bHksIDIwMTcuIE92ZXJhbGwsIHdlIGNhbiBzZWUgdGhlIGF2ZXJhZ2UgcHJpY2UgZm9yIGJvb3RzIGlzIG1vcmUgZmx1Y3R1YXRpbmcgd2hpbGUgcHVtcHMgc2hvZXMgaXMgbW9yZSBzdGFibGUuIApgYGB7cn0KZm9ybWF0KG5ld19kZjIkZGF0ZUFkZGVkLCAiJVktJW0iKSAtPiBuZXdfZGYyJGRhdGVBZGRlZApuZXdfZGYyICU+JSAKICBncm91cF9ieShkYXRlQWRkZWQsIGNhdGVnb3J5KSAlPiUgCiAgc3VtbWFyaXplKAogICAgYXZncHJpY2VfYnlfeW0gPSBtZWFuKHByaWNlcykKICApICU+JSAKICBhcnJhbmdlKGRhdGVBZGRlZCkgLT4gYXZncHJpY2VfYnlfeW0KCmF2Z3ByaWNlX2J5X3ltICU+JSAKICBmaWx0ZXIoY2F0ZWdvcnkgPT0iYm9vdHMiKSAtPmJvb3RzCmF2Z3ByaWNlX2J5X3ltICU+JSAKICBmaWx0ZXIoY2F0ZWdvcnkgPT0icHVtcCIpIC0+cHVtcAoKcCA9IGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGJvb3RzLCBhZXMoeCA9IGRhdGVBZGRlZCwgeSA9IGF2Z3ByaWNlX2J5X3ltLCBjb2xvciA9IGNhdGVnb3J5LCBncm91cCA9IDEpKSsKICAgZ2VvbV9saW5lKGRhdGEgPXB1bXAsIGFlcyh4ID0gZGF0ZUFkZGVkLCB5ID0gYXZncHJpY2VfYnlfeW0sIGNvbG9yID0gY2F0ZWdvcnksIGdyb3VwID0gMSkpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSsKICBsYWJzKHRpdGxlID0gIlRyZW5kIG9mIEF2Zy5QcmljZSBpbiBCb3RoIEJvb3RzIGFuZCBQdW1wIikrCiAgeGxhYigiWWVhci1Nb250aCIpKwogIHlsYWIoIkF2ZXJhZ2UgUHJpY2UiKQoKZ2dwbG90bHkocCkKYGBgCiMjIyBQcmljZSBJbnNwZWN0aW9uIG9uIEJyYW5kCkZpcnN0LCB3ZSBjcmVhdGUgYSBjb3B5IG9mIGRhdGFmcmFtZSBmcm9tIHRoZSBwcmV2aW91cyBwYXJ0LgpgYGB7cn0Kc2hvZXNfcHJpY2UgPC0gbmV3X2RmMgpnbGltcHNlKHNob2VzX3ByaWNlKQpgYGAKCiMjIyMgUG9wdWxhciBCcmFuZHMKVG8gYW5hbHl6ZSB0aGUgcHJpY2UgdHJlbmQgYW1vbmcgZGlzdGluY3QgYnJhbmRzLCB3ZSBjcmVhdGUgYSBsaXN0IG9mIHBvcHVsYXIgYnJhbmRzIGJ5IHRoZSBudW1iZXIgb2Ygc2hvZSBwYWlycyBpbiB0aGlzIGRhdGFzZXQgYW5kIHRoZSBhdmVyYWdlIHByaWNlIG9mIGVhY2ggYnJhbmQsIGJvdGggaW4gZGVzY2VuZGluZyBvcmRlci4gVGhlbiB3ZSBsaXN0IHRoZSB0b3AgMTAgYnJhbmRzIChzZWUgdGFibGUgYmVsb3cpLgpgYGB7cn0KdG9wX2JyYW5kIDwtIHNob2VzX3ByaWNlICU+JSAKICBncm91cF9ieShicmFuZCkgJT4lIAogIHN1bW1hcml6ZShjb3VudCA9IG4oKSwKICAgICAgICAgICAgYnJhbmRfQVZHID0gbWVhbihwcmljZXMsIG5hLnJtID0gVFJVRSkpICU+JSAKICBhcnJhbmdlKGRlc2MoY291bnQpKSAlPiUgCiAgaGVhZCgxMCkKCnRvcF90YmwgPC0gdG9wX2JyYW5kCgpjb2xuYW1lcyh0b3BfdGJsKSA8LSBjKCJCcmFuZCIsICJDb3VudCIsICJCcmFuZCBBdmVyYWdlIikKCnBuZygidG9wNC5wbmciKQp0b3A0IDwtIHRhYmxlR3JvYih0b3BfdGJsLCByb3dzID0gcm93bmFtZXMoTkEpKQpncmlkLmFycmFuZ2UodG9wNCkKYGBgClRoZSBoaWdoZXN0IGBjb3VudGAgb2YgdGhlIHBhaXIgbnVtYmVyIGlzIDEwMDIsIHdoaWNoIGZhbGxzIGluIEJyaW5sZXkgQ28uLiBUaGVyZSBhcmUgdHdvIGJyYW5kcyB3aXRoIGV4dHJlbWVseSBoaWdoIGJyYW5kIGF2ZXJhZ2VzIChhYm92ZSBcJDEwMCksIFNBUyBhbmQgTCdhcnRpc3RlLiBUaGUgdG9wIDUgYnJhbmRzIGFsbCBoYXZlIGBjb3VudGAgYWJvdmUgNDAwIHBhaXJzLCBidXQgdGhlaXIgYnJhbmQgYXZlcmFnZXMgdmFyeSBhbG90LiBUaGUgbmV4dCBzdGVwIGlzIHRvIGNvbXBhcmUgdGhlIHZhcmlhbmNlIGluIHByaWNlcyBmb3IgdGhlc2UgYnJhbmRzLgoKV2UgbWFrZSBhIGJveCBwbG90IG9uIGBicmFuZGAgKGxpc3RlZCBpbiBhbHBoYWJldGljYWwgb3JkZXIgb2YgYnJhbmQgbmFtZXMpLCBhbmQgdGhlIGNvcmFsIGhvcml6b250YWwgbGluZSBpcyB0aGUgbWVhbiBwcmljZSBvZiBhbGwgc2hvZXMgaW4gdGhpcyBkYXRhc2V0LiAKYGBge3J9CnNob2VzX3ByaWNlICU+JQogc2VtaV9qb2luKHRvcF9icmFuZCwgYnkgPSAiYnJhbmQiKSAtPiBwb3BCcmFuZHMKCmdncGxvdChwb3BCcmFuZHMpICsKIGdlb21fYm94cGxvdChhZXMoeCA9IGJyYW5kLCB5ID0gcHJpY2VzLCBjb2wgPSBicmFuZCkpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiM3QzdGOTEiLCAiI0FEREVENCIsICIjQjVENEU5IiwgIiNDM0NFRDkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjQzlFNEI0IiwgIiNDREJDQjYiLCAiI0RCQkRFNSIsICIjRjBDM0EzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRkJDREJFIiwgIiNGREREQUEiKSkgKwogbGFicyh0aXRsZSA9ICJQcmljZSBEaXN0cmlidXRpb24gYnkgQnJhbmRzIiwKICAgICAgeCA9ICJCcmFuZHMiLAogICAgICB5ID0gIlByaWNlIiwKICAgICAgY29sb3IgPSAiQnJhbmQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVkaWFuKHBvcEJyYW5kcyRwcmljZXMsIG5hLnJtID0gVFJVRSksIGNvbG9yID0gImluZGlhbnJlZDMiLCBzaXplID0gMC41LCBhbHBoYSA9IDAuNykgKwogIGdlb21fdGV4dCh4ID0gOSwgeSA9IDMzMCwgbGFiZWwgPSAibWVhbiA9IDcxLjM5IiwgY29sID0gIml2b3J5NCIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE1KSkKYGBgCgpUaGUgYm94IHN0cnVjdHVyZSBpbiBib3ggcGxvdHMgcmVwcmVzZW50cyB3aGVyZSB0aGUgbWlkZGxlIDUwJSBvZiB0aGUgZGF0YSBwb2ludHMgYXJlLCBzbyB3ZSBjYW4gY3Jvc3MtY29tcGFyZSB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0b3AgMTAgYnJhbmRzIGJ5IGNvbXBhcmluZyB0aGUgcG9zaXRpb25zIG9mIGJveGVzIGFyb3VuZCB0aGUgZGF0YXNldCBhdmVyYWdlIGxpbmUuIFRoZSBtYWpvcml0aWVzIG9mIFNBUyBhbmQgTOKAmWFydGlzdGUgaGF2ZSBwcmljZXMgbGFyZ2VyIHRoYW4gdGhlIGRhdGFzZXQgYXZlcmFnZSwgd2hpbGUgdGhlc2UgdHdvIGJyYW5kcyBhbHNvIGhhdmUgdGhlIGhpZ2hlc3QgbWVhbiBwcmljZXMuIFNpbWlsYXJseSwgbW9zdCBzaG9lcyBpbiBCcmlubGV5IENvLiBhbmQgU29kYSBoYXZlIHNtYWxsIHByaWNlcyB0aGFuIHRoZSBkYXRhc2V0IGF2ZXJhZ2UuIAoKU29tZSBvZiB0aGUgYm94IHBsb3RzIGlsbHVzdHJhdGUgdGhlIGVmZmVjdCBvZiB0aGUgb3V0bGllcnMuIEtlZXAgZm9jdXNpbmcgb24gTOKAmWFydGlzdGUsIHdlIGZpbmQgdGhhdCB0aGUgbWlkZGxlIDUwJSBwZXJjZW50aWxlLCBtZWRpYW4sIGFuZCBtZWFuIHByaWNlcyBhcmUgYWxsIG11Y2ggZ3JlYXRlciB0aGFuIHRoZSBkYXRhc2V0IG1lYW4sIGFuZCB0aGlzIG9ic2VydmF0aW9uIGNhbiBiZSBhdHRyaWJ1dGVkIHRvIHRoZSBlZmZlY3Qgb2Ygb3ZlcmFsbCBoaWdoZXIgcHJpY2VzIGFuZCBvdXRsaWVycyBpbiBM4oCZYXJ0aXN0ZS4gSW4gY29udHJhc3QsIEFyZW9zb2xlcywgYW5vdGhlciBicmFuZCB3aXRoIHVuaWdub3JhYmxlIG51bWJlciBvZiBvdXRsaWVycywgaG9sZHMgYSBtZWFuIHByaWNlIHNsaWdodGx5IGhpZ2hlciB0aGFuIHRoZSBkYXRhc2V0IG1lYW4uIFdpdGhvdXQgbG9va2luZyBhdCB0aGUgYm94LCB3ZSBjYW4gaW5mZXIgdGhhdCB0aGUgbWFqb3JpdHkgb2YgcHJpY2VzIGFyZSBzbWFsbGVyIHRoYW4gdGhlIGRhdGFzZXQgbWVhbiwgYW5kIHRoZSBib3ggcGxvdCBjb25maXJtcyB0aGUgaW1wbGljYXRpb24gKHRoZSBtZWRpYW4gb2YgQWVyb3NvbGVzIGlzIGJlbG93IHRoZSBsaW5lKS4gCgojIyMjIFRvcCAzIGJyYW5kcwpUbyBnZXQgYSBzbmlwcGV0IG9mIHRoZSBwb3B1bGFyIHByaWNlIHJhbmdlIGFtb25nIHBvcHVsYXIgc2hvZSBicmFuZHMsIHdlIGNob29zZSB0aGUgdG9wIDMgYnJhbmRzIChCcmlubGV5IENvLiwgU0FTLCBhbmQgVHJvdHRlcnMpIGFuZCBjcmVhdGUgYSBjb21iaW5lZCBkZW5zaXR5IHBsb3QgKGFzIGFuIGFsdGVybmF0aXZlIG9mIGhpc3RvZ3JhbXMpIHdpdGggdmVydGljYWwgbGluZXMgcmVwcmVzZW50aW5nIHRoZSBicmFuZCBtZWFucy4gCmBgYHtyfQp0b3AzIDwtIHRvcF9icmFuZFsxOjMsIF0KCnNob2VzX3ByaWNlICU+JQogc2VtaV9qb2luKHRvcDMsIGJ5ID0gImJyYW5kIikgLT4gc2FtcGxlQnJhbmQKCmdnZGVuc2l0eShzYW1wbGVCcmFuZCwgeCA9ICJwcmljZXMiLCB5ID0gIi4uY291bnQuLiIsIHJ1ZyA9IFRSVUUsCiAgIGFkZCA9ICJtZWFuIiwKICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSBjKCIjN0M3RjkxIiwgIiNDREJDQjYiLCAiI0ZERERBQSIpLCBsaW5ldHlwZSA9ICJsb25nZGFzaCIsIHNpemUgPSAxKSwKICAgY29sb3IgPSAiYnJhbmQiLCBmaWxsID0gImJyYW5kIiwKICAgcGFsZXR0ZSA9IGMoIiNBRERFRDQiLCAiI0I1RDRFOSIsICIjREJCREU1IiksCiAgIHhsYWIgPSAiUHJpY2UiLCB5bGFiID0gIk51bWJlciBvZiBzaG9lcyIsCiAgIHRpdGxlID0gIlByaWNlIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGUgYnJhbmRzIiwKICAgbGVnZW5kID0gInJpZ2h0IikgCmBgYApGaXJzdCwgd2Ugd291bGQgbGlrZSB0byBpbnNwZWN0IHRoZSB0cmVuZHMgaW5kaXZpZHVhbGx5LiBUaGUgZGlzdHJpYnV0aW9ucyBvZiBCcmlubGV5IENvLiBhbmQgU0FTIGFyZSByaWdodC1za2V3ZWQsIHdoaWNoIGlzIHRoZSBlZmZlY3Qgb3V0IGhpZ2ggdmFsdWUgc2hvZXMuIFRyb3R0ZXJzIGRpc3BsYXlzIGEgcmVsYXRpdmVseSDigJxiaW5vbWlhbOKAnSBkaXN0cmlidXRpb24sIGJlY2F1c2UgdGhlIHByaWNlcyB0ZW5kIHRvIGRpdmVyZ2UgdG8gdGhlIGVkZ2VzIGluc3RlYWQgb2YgbWVyZ2luZyBhdCB0aGUgY2VudGVyLiBUaGVuIHdlIG9ic2VydmUgdHdvIG92ZXJsYXBwaW5nIGFyZWFzOiBvbmUgaXMgWzQwLCA2MF0gYW5kIHRoZSBvdGhlciBpcyBbMTEwLCAxNjBdLiAKCldlIGNhbiBkZWZpbmUgdGhlc2UgdHdvIHJhbmdlcyBhcyB0aGUg4oCccG9wdWxhcuKAnSBvbmVzIGJhc2VkIG9uIHRoZSBzYW1wbGUgcHJvcGVydGllcy4gVG9wIDMgYnJhbmRzIGNvdmVyIG5lYXJseSAyMCUgKCooMTAwMiArIDQ1NSArIDQ1MSkvOTcwOSopIG9mIHRoZSBzaG9lcy4gU3VjaCBwb3J0aW9uIG9mIHRoZSBkYXRhIHNpemUgY2FuIHNvbWVob3cgcmVmbGVjdCB0aGUgcmV0YWlsZXLigJlzIGZhdm9yLiBBbm90aGVyIGludGVyZXN0aW5nIHBhdHRlcm4gaW4gdGhpcyBzYW1wbGUgaXMgdGhlIHJlbGF0aXZlIGxvY2F0aW9uIG9mIHByaWNlIHN0YXRpc3RpY3MgKG1lYW4pLiBCcmlubGV5IENvLiBhbmQgU0FTIGhhdmUgZXh0cmVtZSBtZWFuIHZhbHVlcyAoYXMgd2UgaGF2ZSBtZW50aW9uZWQgaW4gdGhlIGJveCBwbG90KS4gVHJvdHRlcnMgaGFzIGEgbWVhbiBvZiBcJDgzLCBwcmV0dHkgY2xvc2UgdG8gdGhlIG92ZXJhbGwgbWVhbi4gVGhpcyBwYXR0ZXJuIG1ha2VzIHRoZSAzLW9ic2VydmF0aW9uIHNhbXBsZSBxdWl0ZSByZXByZXNlbnRhdGl2ZTsgYWxvbmcgd2l0aCB0aGVpciBwb3B1bGFyaXRpZXMsIHdlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSBvdmVybGFwcGVkIHJhbmdlcyBhcmUgcmVsaWFibGUgdG8gc3VnZ2VzdCB0aGUgcG9wdWxhciByYW5nZXMuCgojIyMjIE92ZXJhbGwgVHJlbmQKQXQgdGhlIGVuZCBvZiB0aGUgcHJpY2UgaW5zcGVjdGlvbiwgd2UgcGxvdCBhIGRlbnNpdHkgZ3JhcGggZm9yIGFsbCBzaG9lIHByaWNlcyByZWdhcmRsZXNzIG9mIHRoZWlyIGNhdGVnb3JpZXMgYW5kIGJyYW5kczoKYGBge3J9CmRpc3RfYWxsIDwtIGdnZGVuc2l0eShzaG9lc19wcmljZSwgeCA9ICJwcmljZXMiLCB5ID0gIi4uY291bnQuLiIscnVnID0gVFJVRSwgCiAgICAgICAgICBmaWxsID0gIiNBRERFRDQiLCBjb2xvciA9ICIjQURERUQ0IiwgYWxwaGEgPSAwLjcsCiAgICAgICAgICBhZGQgPSAibWVhbiIsIAogICAgICAgICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiIzdDN0Y5MSIsIGxpbmV0eXBlID0gImxvbmdkYXNoIiwgc2l6ZSA9IDEpLAogICAgICAgICAgeGxhYiA9ICJBdmVyYWdlIFByaWNlIiwgeWxhYiA9ICJOdW1iZXIgb2Ygc2hvZXMiLAogICAgICAgICAgbWFpbiA9ICJQcmljZSBkaXN0cmlidXRpb24gb2Ygc2hvZXMiKSArIAogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCAzMDApKSArIAogIHRoZW1lX2NsYXNzaWMoKQoKZ2dwbG90bHkoZGlzdF9hbGwpICU+JSAKICBsYXlvdXQodGl0bGUgPSBsaXN0KHRleHQgPSBwYXN0ZTAoIlByaWNlIGRpc3RyaWJ1dGlvbiBvZiBzaG9lcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwvc3VwPiIpKSkKYGBgClRoZSBvdmVyYWxsIHRyZW5kIGlzIHJpZ2h0LXNrZXdlZCwgZXZlbiBhZnRlciB3ZSBoYXZlIHJlbW92ZWQgb3V0bGllcnMgKFwkNTAwIGFuZCBhYm92ZSkuIEFzIHdlIGhhdmUgb2JzZXJ2ZWQgaW4gdGhlIGNhdGVnb3J5IGJveCBwbG90LCBtb3N0IHByaWNlcyBmYWxsIGJlbG93IFwkMTAwLiBTbyBpZiB3ZSBzZXQgXCQxMDAgYXMgYW4gdXBwZXIgYm91bmQgdG8gb3VyIGRhdGEgcG9vbCwgdGhlIG92ZXJhbGwgZGlzdHJpYnV0aW9uIHdvdWxkIGxvb2sgbW9yZSDigJxub3JtYWzigJ0sIHdoaWNoIGNvcnJlc3BvbmRzIHRoZSBzdGF0aXN0aWNhbCBsZW1tYSB0aGF0IGEgbGFyZ2VyIHNhbXBsZSBzaXplIChjb21wYXJlZCB0byBzaW5nbGUgYnJhbmQgdHJlbmQpIHRlbmRzIHRvIGRpc3BsYXkgYSBtb3JlICJOb3JtYWwiIGRpc3RyaWJ1dGlvbi4gTW9yZW92ZXIsIHRoZXJlIGFyZSB0d28gZGVuc2l0eSBwZWFrcywgWzQ1LCA2MF0gYW5kIFsxMjAsIDE1MF0sIHdoaWNoIGFsc28gb3ZlcmxhcHMgd2l0aCB0aGUgcG9wdWxhciByYW5nZSBvZiBUb3AgMyBicmFuZHMuIEhlbmNlIHdlIGNhbiBjb25zaWRlciB0aGVzZSByYW5nZXMgYXMg4oCccG9wdWxhcuKAnSB0byByZXRhaWxlcnMuCgotLS0tLS0KCiMjIENvbmNsdXNpb25zCldlIGhhdmUgYW5hbHl6ZWQgYSBzYW1wbGUgb2YgfjksNzAwIG9mIG9ubGluZSB3b21lbidzIHNob2VzIGxpc3RpbmdzIGFuZCBjYW1lIHRvIGNvbmNsdXNpb24gdGhhdCBtb3N0IGJyYW5kcyB0ZW5kIHRvIG9mZmVyIG1vcmUgbG93IHByaWNlcyBzaG9lcyByYXRoZXIgdGhhbiBoaWdoIHByaWNlcyBvbmVzLiBBbHRob3VnaCBzb21lIGJyYW5kcyBvZmZlciBleHBlbnNpdmUgc2hvZXMsIHRoZXkgYWxzbyBoYXZlIGNoZWFwIG9wdGlvbnMuIFRoaXMgb2JzZXJ2YXRpb24gaW5kaWNhdGVzIHRoYXQgYnJhbmRzIHRlbmQgdG8gdGFyZ2V0IGxvdyB0byBtZWRpdW0gbGV2ZWwgaW5jb21lIGF1ZGllbmNlIGJ5IG9mZmVyaW5nICJhZmZvcmRhYmxlIHByaWNlcyIuIAoKV2UgaGF2ZSBhbHNvIGlkZW50aWZpZWQgdGhlIHByaWNlIGRpc3RyaWJ1dGlvbnMgaW4gY2F0ZWdvcnkgYW5kIGJyYW5kLiBUaGUgZ2VuZXJhbCBkaXN0cmlidXRpb24gcGF0dGVybiBpcyByaWdodC1za2V3ZWQuIEluIHRlcm1zIG9mIHBvcHVsYXIgcHJpY2VzLCBicmFuZHMgdXN1YWxseSBrZWVwIHRoZWlyIHByaWNlIGludGVydmFsIGxlc3MgdGhhbiBcJDM1MC4gV2UgaGF2ZSBhbHNvIG9ic2VydmVkIHRoYXQgdGhlIGxhcmdlciBzYW1wbGUgc2l6ZSB0ZW5kcyB0byBlbXBsb3kgYSBtb3JlIOKAnE5vcm1hbOKAnSBkaXN0cmlidXRpb24uIAoKSW4gYWRkaXRpb24sIHdlIGhhdmUgbm90aWNlZCBzb21lIGNhdGVnb3JpY2FsIHRyZW5kcy4gQmxhY2ssIHdoaXRlLCBzaGFkZXMgYW5kIGJlaWdlIHNob2VzIGtlZXAgZWFybmluZyBmYXZvcnMgaW4gZGlmZmVyZW50IHNlYXNvbnMuIFNpemUgNyBhbmQgOCBoYXZlIGEgbGFyZ2VyIHBvdGVudGlhbCBjdXN0b21lciBncm91cC4gTW9zdCBtYW51ZmFjdHVyZXMgdGVuZCB0byBsYXVuY2ggbmV3IHByb2R1Y3RzIGluIEFwcmlsIGFuZCBTZXB0ZW1iZXIuIEFsbCB0aGVzZSB0cmVuZHMgY291bGQgcmVmbGVjdCBzaG9lIGluZHVzdHJ5J3MgcHJlZmVyZW5jZSBmcm9tIDIwMTUgdG8gMjAxOSwgYW5kIGZhc2hpb24gYW5hbHlzdHMgY291bGQgcHJlZGljdCBmdXR1cmUgdHJlbmRzIHdpdGggbW9yZSByZXNlYXJjaC4KCkJhc2VkIG9uIHRoZSBzdW1tYXJ5LCB3ZSB3b3VsZCBiZSBhYmxlIHRvIHByb3ZpZGUgc29tZSByZWNvbW1lbmRhdGlvbnMgdG8gdGhvc2Ugd2hvIGFyZSByZWZlcnJpbmcgdG8gYFdvbWVuJ3MgU2hvZXNgIGRhdGFzZXQuIFdoZW4gcHVyY2hhc2luZyBwcm9kdWN0cywgcmV0YWlsZXJzIGNvdWxkIGZvY3VzIG1vcmUgb24gYmxhY2sgYW5kIHdoaXRlIHNob2VzLCBvciBvdGhlciBjb2xvciB0b25lcyBpbiByZXNwb25zZSB0byBzZWFzb24gY2hhbmdlLiBUaGV5IG1heSBhbHNvIG5lZWQgdG8gaWRlbnRpZnkgdGFyZ2V0IGdyb3VwcyBvZiBjdXN0b21lcnMgZmlyc3QgdG8gc2V0IHByaWNlIGZvciBzaG9lcy4gVHdvIGZyZXF1ZW50IHJhbmdlcywgXCQ0NSAtIFwkNjAgYW5kIFwkMTIwIC0gXCQxNTAsIGNhbiBiZSByZWZlcmVuY2VzIG9uIGN1c3RvbWVyJ3MgcHJlZmVyZW5jZSBiYXNlZCBvbiBkaWZmZXJlbnQgdHlwZXMgb2Ygc2hvZXMu